//识别贴纸图案
#include"Dector.hpp"

//对于识别贴纸图案，有很多思路，我用的是模板匹配，比较简单一点

//执行单个模板匹配
void TemplateMatcher::singleMatch(const cv::Mat& templ, const std::string& label)
{
    cv::Mat result;   
    int result_cols = img.cols - templ.cols + 1;      //原来图像尺寸为W*H，模板图像尺寸为w*h，那么结果图像尺寸一定为（W-w+1）*（H-h+1）
    int result_rows = img.rows - templ.rows + 1;
    result.create(result_cols, result_rows, CV_32FC1);       //创建结果矩阵，数据类型为单通道32位浮点型
    cv::matchTemplate(img, templ, result, cv::TM_SQDIFF_NORMED);    //使用归一化平方差匹配方法进行模板匹配
    cv::normalize(result, result, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());    //对匹配结果进行归一化处理，使结果值在0到1之间
    double minVal, maxVal;  
    cv::Point minLoc, maxLoc;
    cv::minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat());  //查找结果矩阵中的最小值、最大值及其对应的位置
    cv::Point matchLoc = minLoc;   //归一化平方差匹配下，最小值对应的位置为匹配位置
    cv::Point center = cv::Point(minLoc.x + templ.cols / 2, minLoc.y + templ.rows / 2);  //计算匹配区域的中心位置
    //绘制矩形，进行可视化
    cv::rectangle(img, matchLoc, cv::Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), cv::Scalar(0, 255, 0), 5); 
    //获取标签文本的大小
    int baseline = 0;
    cv::Size textSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 1, 4, &baseline);
    // 计算文本起始坐标，使其位于矩形顶部居中
    int x = matchLoc.x + (templ.cols - textSize.width) / 2;
    int y = matchLoc.y - baseline;
    //绘制文本
    cv::putText(img, label, cv::Point(x, y), cv::FONT_HERSHEY_SIMPLEX, 1.5, cv::Scalar(255, 0, 0), 5);
}

//构造函数
TemplateMatcher::TemplateMatcher(const std::string& imgPath, 
const std::vector<std::string>& templatePaths,const std::vector<std::string>& labels)
{
    img = cv::imread(imgPath);   //通过图像路径读取待匹配的图像
    for (const std::string& path : templatePaths) {    //遍历模板路径列表，读取每个模板图像并存储到templates
        templates.push_back(cv::imread(path));     
    }
}

//执行所有模板匹配
void TemplateMatcher::performAllMatches(const std::vector<std::string>& labels)
{   
    //遍历所有模板图像
    for (int i = 0; i < templates.size(); i++) {
    singleMatch(templates[i], labels[i]);   //调用singleMatch函数进行单个模板匹配
    }
    cv::imshow("img", img);  //显示图像
    cv::waitKey(0);   //等待用户按键，按任意键后关闭显示窗口
}
